/*
 * File RdfDB.java
 */
package diskmgr;

import java.io.*;

import bufmgr.*;
import global.*;
import heap.Heapfile;
import labelheap.*;
import labelheap.SpaceNotAvailableException;
import tripleheap.*;
import tripleheap.InvalidSlotNumberException;
import iterator.*;
import btree.*;

public class RdfDB implements GlobalConst {

	private static final int bits_per_page = MAX_SPACE * 8;
	private LabelHeapFile entityLabelHeap;
	private LabelHeapFile predicateLabelHeap;
	private TripleHeapfile tripleHeap;
	private final static boolean OK = true;
	private final static boolean FAIL = false;
	private PID p;
	private EID e;
	private LID l;
	private TID t;
	private TScan tsc;

	/**
	 * default constructor.
	 */
	public RdfDB() {}

	public void deleteEntityIndex(String entityLabel) throws ScanDeleteException, KeyNotMatchException, IteratorException, ConstructPageException, PinPageException, UnpinPageException, IOException, ScanIteratorException
	{
		KeyClass key = new StringKey(entityLabel);
		BTFileScanL scan = SystemDefs.entityLIDIndex.new_scan(key, key);
		KeyDataEntry entry = scan.get_next();
		if(entry !=null)
		{
			scan.delete_current();
		}

	}

	public void deletePredicateIndex(String predicateLabel) throws KeyNotMatchException, IteratorException, ConstructPageException, PinPageException, UnpinPageException, IOException, ScanIteratorException, ScanDeleteException 
	{
		KeyClass key = new StringKey(predicateLabel);
		BTFileScanL scan = SystemDefs.predicateLIDIndex.new_scan(key, key);
		KeyDataEntry entry = scan.get_next();
		if(entry !=null)
		{
			scan.delete_current();
		}

	}

	public void funcdeleteTripleIndex(BTFileScan scan,double confidence,TID tt) throws InvalidSlotNumberException, InvalidTripleSizeException, THFException, THFDiskMgrException, THFBufMgrException, Exception
	{

		TID tid = null;
		KeyDataEntry entry = scan.get_next();
		while(entry!=null)
		{
			LeafData ld = (LeafData)(entry.data);
			tid = ld.getData();
			Triple triple = SystemDefs.tripleHeap.getTriple(tid);
			byte[] tdata = triple.getTripleByteArray();
			double curConf = Convert.getDblValue(24, tdata);
			String ttStr = tt.pageNo + "," + tt.slotNo;
			String tidStr = tid.pageNo + "," + tid.slotNo;
			if(curConf == confidence && ttStr.equals(tidStr))
			{
				//delete from index file
				scan.delete_current();
				break;

			}
			entry = scan.get_next();
		}

	}

	public void deleteTripleIndex(byte[] spoData, double confidence,TID tt) throws InvalidSlotNumberException, InvalidTripleSizeException, THFException, THFDiskMgrException, THFBufMgrException, Exception  
	{
		String spo = Convert.getStrValue(0, spoData, spoData.length);
		KeyClass key = new StringKey(spo);
		BTFileScan scan = SystemDefs.compTID_SPO_Index.new_scan(key, key);
		funcdeleteTripleIndex(scan,confidence,tt);

		int subpageno=Convert.getIntValue(0, spoData);
		PageId pageid=new PageId();
		pageid.pid=subpageno;
		int subslotno=Convert.getIntValue(4, spoData);
		LID tempL=new LID(pageid,subslotno);
		String subject=entityLabelHeap.getLabel(tempL);

		int Pre=Convert.getIntValue(8, spoData);
		pageid=new PageId();
		pageid.pid=Pre;
		int preslotno=Convert.getIntValue(12, spoData);
		tempL=new LID(pageid,preslotno);
		String predicate=predicateLabelHeap.getLabel(tempL);

		int obj=Convert.getIntValue(16, spoData);
		pageid=new PageId();
		pageid.pid=obj;
		int objslotno=Convert.getIntValue(20, spoData);
		tempL=new LID(pageid,objslotno);
		String object=entityLabelHeap.getLabel(tempL);

		String subpre=subject+","+predicate;
		key = new StringKey(subpre);
		scan = SystemDefs.compTID_SP_Index.new_scan(key, key);
		funcdeleteTripleIndex(scan,confidence,tt);

		String preobj=predicate+","+object;
		key = new StringKey(preobj);
		scan = SystemDefs.compTID_PO_Index.new_scan(key, key);
		funcdeleteTripleIndex(scan,confidence,tt);

		String subcon=subject+","+confidence;
		key = new StringKey(subcon);
		scan = SystemDefs.compTID_SC_Index.new_scan(key, key);
		funcdeleteTripleIndex(scan,confidence,tt);

		String precon=predicate+","+confidence;
		key = new StringKey(precon);
		scan = SystemDefs.compTID_PC_Index.new_scan(key, key);
		funcdeleteTripleIndex(scan,confidence,tt);

		String obcon=object+","+confidence;
		key = new StringKey(obcon);
		scan = SystemDefs.compTID_OC_Index.new_scan(key, key);
		funcdeleteTripleIndex(scan,confidence,tt);

		String subobj=subject+","+object;
		key = new StringKey(subobj);
		scan = SystemDefs.compTID_SO_Index.new_scan(key, key);
		funcdeleteTripleIndex(scan,confidence,tt);

		key = new StringKey(subject);
		scan = SystemDefs.subTIDBTIndex.new_scan(key, key);
		funcdeleteTripleIndex(scan,confidence,tt);
		

		key = new StringKey(object);
		scan = SystemDefs.objTIDBTIndex.new_scan(key, key);
		funcdeleteTripleIndex(scan,confidence,tt);

		key = new StringKey(predicate);
		scan = SystemDefs.predTIDBTIndex.new_scan(key, key);
		funcdeleteTripleIndex(scan,confidence,tt);
		

		//key = new DoubleKey(confidence);
		//scan = SystemDefs.confTIDBTIndex.new_scan(key, key);
		//funcdeleteTripleIndex(scan,confidence,tt);
	}
	
	public void insertTripleIndex(byte[] spo, double confidence, TID tid) 
	throws labelheap.InvalidSlotNumberException, InvalidLabelSizeException, LHFException, LHFDiskMgrException, LHFBufMgrException, Exception
	{
		String spoStr = Convert.getStrValue(0, spo, spo.length);
		KeyClass key = new StringKey(spoStr);
		SystemDefs.compTID_SPO_Index.insert(key, tid);

		int subpageno=Convert.getIntValue(0, spo);
		PageId pageid=new PageId();
		pageid.pid=subpageno;
		int subslotno=Convert.getIntValue(4, spo);
		LID tempL=new LID(pageid,subslotno);
		String subject=entityLabelHeap.getLabel(tempL);

		int Pre=Convert.getIntValue(8, spo);
		pageid=new PageId();
		pageid.pid=Pre;
		int preslotno=Convert.getIntValue(12, spo);
		tempL=new LID(pageid,preslotno);
		String predicate=predicateLabelHeap.getLabel(tempL);

		int obj=Convert.getIntValue(16, spo);
		pageid=new PageId();
		pageid.pid=obj;
		int objslotno=Convert.getIntValue(20, spo);
		tempL=new LID(pageid,objslotno);
		String object=entityLabelHeap.getLabel(tempL);

		String subpre=subject+","+predicate;
		key = new StringKey(subpre);
		SystemDefs.compTID_SP_Index.insert(key, tid);

		String preobj=predicate+","+object;
		key = new StringKey(preobj);
		SystemDefs.compTID_PO_Index.insert(key, tid);

		String subcon=subject+","+confidence;
		key = new StringKey(subcon);
		SystemDefs.compTID_SC_Index.insert(key, tid);

		String precon=predicate+","+confidence;
		key = new StringKey(precon);
		SystemDefs.compTID_PC_Index.insert(key, tid);

		String obcon=object+","+confidence;
		key = new StringKey(obcon);
		SystemDefs.compTID_OC_Index.insert(key, tid);

		String subobj=subject+","+object;
		key = new StringKey(subobj);
		SystemDefs.compTID_SO_Index.insert(key, tid);

		key = new StringKey(subject);
		SystemDefs.subTIDBTIndex.insert(key, tid);

		key = new StringKey(object);
		SystemDefs.objTIDBTIndex.insert(key, tid);

		key = new StringKey(predicate);
		SystemDefs.predTIDBTIndex.insert(key, tid);

		//key = new DoubleKey(confidence);
		//SystemDefs.confTIDBTIndex.insert(key, tid);
	}

	public EID searchEntityinIndexfile(String entity) 
	throws KeyNotMatchException, 
	IteratorException, 
	ConstructPageException, 
	PinPageException, 
	UnpinPageException, 
	IOException, 
	ScanIteratorException
	{
		KeyClass key = new StringKey(entity);
		BTFileScanL scan = SystemDefs.entityLIDIndex.new_scan(key, key);
		KeyDataEntry entry = scan.get_next();
		if(entry !=null)
		{
			LeafDataL ldata = (LeafDataL)entry.data;
			LID lid = ldata.getData();
			EID eid = new EID(lid);
			return eid;
		}
		else 
			return null;
	}

	public PID searchPredicateinIndexfile(String predicate) 
	throws ScanIteratorException, 
	KeyNotMatchException, 
	IteratorException, 
	ConstructPageException, 
	PinPageException, 
	UnpinPageException, 
	IOException
	{
		KeyClass key = new StringKey(predicate);
		BTFileScanL scan = SystemDefs.predicateLIDIndex.new_scan(key, key);
		KeyDataEntry entry = scan.get_next();
		if(entry !=null)
		{
			LeafDataL ldata = (LeafDataL)entry.data;
			LID lid = ldata.getData();
			PID pid = new PID(lid);
			return pid;
		}
		else
			return null;
	}



	public TID searchTripleinIndexfile(byte[] sub_pred_obj, double confidence) 
	throws InvalidSlotNumberException, InvalidTripleSizeException, THFException, THFDiskMgrException, THFBufMgrException, Exception
	{
		TID tid=null;
		String spo = Convert.getStrValue(0, sub_pred_obj, sub_pred_obj.length);
		KeyClass key = new StringKey(spo);
		BTFileScan scan = SystemDefs.compTID_SPO_Index.new_scan(key, key);
		KeyDataEntry entry = scan.get_next();
		while(entry!=null)
		{
			LeafData ld = (LeafData)(entry.data);
			tid = ld.getData();
			Triple triple = SystemDefs.tripleHeap.getTriple(tid);
			byte[] tdata = triple.getTripleByteArray();
			double curConf = Convert.getDblValue(24, tdata);
			if(curConf > confidence)
			{
				//delete from index file
				//scan.delete_current();
				deleteTriple(sub_pred_obj,curConf,tid);
				//delete from heap file
				//SystemDefs.tripleHeap.deleteTriple(tid);
				return null;	
				//break;
			}
			entry = scan.get_next();
		}
		return tid;
	}
	
	// Removes the given triple from the database.
	public boolean deleteTriple(byte[] sub_pred_obj,double confidence,TID tt) throws THFException, Exception {
		//double confidence = Convert.getDblValue(24, triplePtr);
		//String sub_pred_obj=Convert.getStrValue(0, triplePtr, 24);
		
		//t=searchTripleinIndexfile(sub_pred_obj,confidence);
		//t=tripleHeap.searchTriple(triplePtr);
		if (tt != null) {
			deleteTripleIndex(sub_pred_obj, confidence,tt);
			Stats.tcounter--;
			return tripleHeap.deleteTriple(tt);
		}
		return false;
	}

	public void insertEntityIndex(String entity, LID lid) 
	throws KeyTooLongException, 
	KeyNotMatchException, 
	LeafInsertRecException, 
	IndexInsertRecException, 
	ConstructPageException, 
	UnpinPageException, 
	PinPageException, 
	NodeNotMatchException, 
	ConvertException, 
	DeleteRecException, 
	IndexSearchException, 
	IteratorException, 
	LeafDeleteException, 
	InsertException, 
	IOException
	{
		KeyClass key = new StringKey(entity);
		SystemDefs.entityLIDIndex.insert(key, lid);
	}

	public void insertPredicateIndex(String predicate, LID lid) 
	throws KeyTooLongException, 
	KeyNotMatchException, 
	LeafInsertRecException, 
	IndexInsertRecException, 
	ConstructPageException, 
	UnpinPageException, 
	PinPageException, 
	NodeNotMatchException, 
	ConvertException, 
	DeleteRecException, 
	IndexSearchException, 
	IteratorException, 
	LeafDeleteException, 
	InsertException, 
	IOException
	{
		KeyClass key = new StringKey(predicate);
		SystemDefs.predicateLIDIndex.insert(key, lid);
	}


	/*
	 * Parameterized constructor.
	 */
	public RdfDB(int type) {
		// type denotes the type of indexing, clustering strategies that will be
		// useds.
	}

	// Returns the number of triples in the database.
	int getTripleCnt() throws tripleheap.InvalidSlotNumberException, InvalidTripleSizeException, THFDiskMgrException, THFBufMgrException, IOException {
		return tripleHeap.getTripleCnt();
	}

	// Returns the number of entities in the database.
	int getEntityCnt() throws labelheap.InvalidSlotNumberException, InvalidLabelSizeException, LHFDiskMgrException, LHFBufMgrException, IOException {
		return entityLabelHeap.getLabelCnt();
	}

	// Returns the number of predicates in the database
	int getPredicateCnt() throws labelheap.InvalidSlotNumberException, InvalidLabelSizeException, LHFDiskMgrException, LHFBufMgrException, IOException {
		return predicateLabelHeap.getLabelCnt();
	}

	// Returns the number of distinct subjects in the database.
	int getSubjectCnt() {
		int subjectCount = 0;
		TScan tsc1;
		TID tid = new TID();
		EID e1, e2;
		LID l1, l2;
		Label lab1 = new Label(), lab2 = new Label();

		try {
			tsc = tripleHeap.openScan();
		} catch (Exception e) {
			System.err.println("*** Error opening scan\n");
			e.printStackTrace();
		}

		Triple triple = new Triple();
		Triple triple1 = new Triple();

		boolean done = false;
		while (!done) {
			try {
				triple = tsc.getNext(tid);
				if (triple == null) {
					done = true;
					break;
				}
				e1 = triple.getSubjectID();
				tsc1 = tripleHeap.openScan();
				l1 = e1.returnLID();
				lab1.setLabel(entityLabelHeap.getLabel(l1));

				TID tid1 = new TID();
				boolean flag = true;
				while (true) {
					triple1 = tsc1.getNext(tid1);
					e2 = triple.getSubjectID();
					l2 = e2.returnLID();
					lab2.setLabel(entityLabelHeap.getLabel(l2));

					if (TripleUtils.Equal(triple, triple1) || LabelUtils.Equal(lab1, lab2)) {
						flag = false;
						break;
					}
				}
				tsc1.closescan();
				if (flag == true)
					subjectCount++;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		return subjectCount;
	}

	// Returns the number of distinct objects in the database.
	int getObjectCnt() {
		int objectCount = 0;
		TScan tsc1;
		TID tid = new TID();
		EID e1, e2;
		LID l1, l2;
		Label lab1 = new Label(), lab2 = new Label();

		try {
			tsc = tripleHeap.openScan();
		} catch (Exception e) {
			System.err.println("*** Error opening scan\n");
			e.printStackTrace();
		}

		Triple triple = new Triple();
		Triple triple1 = new Triple();

		boolean done = false;
		while (!done) {
			try {
				triple = tsc.getNext(tid);
				if (triple == null) {
					done = true;
					break;
				}
				e1 = triple.getObjectID();
				tsc1 = tripleHeap.openScan();
				l1 = e1.returnLID();
				lab1.setLabel(entityLabelHeap.getLabel(l1));

				TID tid1 = new TID();
				boolean flag = true;
				while (true) {
					triple1 = tsc1.getNext(tid1);
					e2 = triple.getObjectID();
					l2 = e2.returnLID();
					lab2.setLabel(entityLabelHeap.getLabel(l2));

					if (TripleUtils.Equal(triple, triple1) || LabelUtils.Equal(lab1, lab2)) {
						flag = false;
						break;
					}
				}
				tsc1.closescan();
				if (flag == true)
					objectCount++;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		return objectCount;
	}

	/*
	 * Inserts the given entity label into the database and return its entity
	 * id. The insertEntity() method ensures that there is only one entity with
	 * a given entity label in the database.
	 */
	public EID insertEntity(java.lang.String EntityLabel) throws InvalidLabelSizeException, labelheap.InvalidSlotNumberException, LHFBufMgrException, LHFDiskMgrException, SpaceNotAvailableException, LHFException, IOException, KeyNotMatchException, IteratorException, ConstructPageException, PinPageException, UnpinPageException, ScanIteratorException, KeyTooLongException, LeafInsertRecException, IndexInsertRecException, NodeNotMatchException, ConvertException, DeleteRecException, IndexSearchException, LeafDeleteException, InsertException {
		e=searchEntityinIndexfile(EntityLabel);
		//l=entityLabelHeap.searchLabel(EntityLabel.getBytes());
		if(e==null){
			l = entityLabelHeap.insertLabel(EntityLabel.getBytes());

			insertEntityIndex(EntityLabel, l);
			Stats.enIncrement();
			e = new EID(l);
			return e;
		}
		//else
		//e = new EID(l);
		return e;
	}

	/*
	 * Removes the given entity label from the database.
	 */
	public boolean deleteEntity(java.lang.String EntityLabel) throws LHFException,
	Exception {

		//e=searchEntityinIndexfile(EntityLabel);
		//l=e.returnLID();
		l=entityLabelHeap.searchLabel(EntityLabel.getBytes());
		if (l != null) {
			//deleteEntityIndex(EntityLabel);
			return entityLabelHeap.deleteLabel(l);
		}
		return false;
	}

	/*
	 * Inserts the given predicate la- bel into the database and return its
	 * predicate id. The insertPredicate() method ensures that there is only one
	 * predicate with a given entity label in the database.
	 */
	public PID insertPredicate(java.lang.String PredicateLabel) throws InvalidLabelSizeException, labelheap.InvalidSlotNumberException, LHFBufMgrException, LHFDiskMgrException, SpaceNotAvailableException, LHFException, IOException, ScanIteratorException, KeyNotMatchException, IteratorException, ConstructPageException, PinPageException, UnpinPageException, KeyTooLongException, LeafInsertRecException, IndexInsertRecException, NodeNotMatchException, ConvertException, DeleteRecException, IndexSearchException, LeafDeleteException, InsertException {

		//search in predicatebtree if null
		//call insert of heap
		//call insert of predicate btree
		p=searchPredicateinIndexfile(PredicateLabel);
		//l=predicateLabelHeap.searchLabel(PredicateLabel.getBytes());
		if (p == null) {
			l = predicateLabelHeap.insertLabel(PredicateLabel.getBytes());
			insertPredicateIndex(PredicateLabel,l);
			Stats.prIncrement();
			p = new PID(l);
			return p;
		}
		//else
		//p = new PID(l);
		return p;
	}

	/*
	 * Removes the given predicate label from the database.
	 */
	public boolean deletePredicate(java.lang.String PredicateLabel)
	throws LHFException, Exception {
		//p=searchPredicateinIndexfile(PredicateLabel);
		//l=p.returnLID();
		l=predicateLabelHeap.searchLabel(PredicateLabel.getBytes());
		if (l != null) {
			//deletePredicateIndex(PredicateLabel);
			return (predicateLabelHeap.deleteLabel(l));
		}
		return false;
	}

	/*
	 * Inserts the given triple into the database and return its triple id. The
	 * insertTriple() method ensures that there is only one triple with the same
	 * subject, pred- icate, and object. If a second one is attempted to be
	 * inserted, only the one with the smallest confidence is maintained in the
	 * database.
	 */
	public TID insertTriple(byte[] triplePtr) throws THFException, InvalidSlotNumberException, InvalidTripleSizeException, tripleheap.SpaceNotAvailableException, THFBufMgrException, THFDiskMgrException, HFException, HFBufMgrException, IOException, Exception {

		double confidence = Convert.getDblValue(24, triplePtr);
		//String sub_pred_obj=Convert.getStrValue(0, triplePtr, 24);
		byte[] sub_pred_obj=new byte[24];
		//System.arraycopy(triplePtr,0,sub_pred_obj,0,sub_pred_obj.length);
		int subpid = Convert.getIntValue(0, triplePtr);
		int subSlot = Convert.getIntValue(4, triplePtr);
		int predpid = Convert.getIntValue(8, triplePtr);
		int predSlot = Convert.getIntValue(12, triplePtr);
		int objpid = Convert.getIntValue(16,triplePtr);
		int objSlot = Convert.getIntValue(20, triplePtr);

		Convert.setIntValue(subpid, 0, sub_pred_obj);
		Convert.setIntValue(subSlot, 4, sub_pred_obj);
		Convert.setIntValue(predpid, 8, sub_pred_obj);
		Convert.setIntValue(predSlot, 12, sub_pred_obj);
		Convert.setIntValue(objpid, 16, sub_pred_obj);
		Convert.setIntValue(objSlot, 20, sub_pred_obj);


		t=searchTripleinIndexfile(sub_pred_obj,confidence);
		//t=tripleHeap.searchTriple(triplePtr);
		if (t == null)
		{
			t=tripleHeap.insertTriple(triplePtr);
			insertTripleIndex(sub_pred_obj, confidence , t);
			Stats.tIncrement();
			return t;
		}
		return t;
	}

	public void createLabelIndexFiles() 
	throws GetFileEntryException, 
	ConstructPageException, 
	AddFileEntryException, 
	IOException
	{
		SystemDefs.entityLIDIndex = new BTreeFileL(ENTITY_LID_INDEXFILE, AttrType.attrString, 100, 0 /*deletefashion- naive delete*/);
		SystemDefs.predicateLIDIndex = new BTreeFileL(PREDICATE_LID_INDEXFILE, AttrType.attrString, 100, 0 /*deletefashion- naive delete*/);
	}

	public void createTripleIndexFiles() throws GetFileEntryException, ConstructPageException, AddFileEntryException, IOException
	{
		SystemDefs.subTIDBTIndex = new BTreeFile(SUBJECT_TID_INDEXFILE, AttrType.attrString, 100, 0 /*deletefashion- naive delete*/);
		SystemDefs.predTIDBTIndex = new BTreeFile(PREDICATE_TID_INDEXFILE, AttrType.attrString, 100, 0 /*deletefashion- naive delete*/);
		SystemDefs.objTIDBTIndex = new BTreeFile(OBJECT_TID_INDEXFILE, AttrType.attrString, 100, 0 /*deletefashion- naive delete*/);
		//SystemDefs.confTIDBTIndex = new BTreeFile(CONF_TID_INDEXFILE, AttrType.attrDouble, 8, 1 /*deletefashion- naive delete*/);

		SystemDefs.compTID_SP_Index = new BTreeFile(SUB_PRED_COMPOSITEINDEX, AttrType.attrString, 100, 0 /*deletefashion- naive delete*/);
		SystemDefs.compTID_PO_Index = new BTreeFile(PRED_OBJ_COMPOSITEINDEX, AttrType.attrString, 100, 0 /*deletefashion- naive delete*/);
		SystemDefs.compTID_SC_Index = new BTreeFile(SUB_CON_COMPOSITEINDEX, AttrType.attrString, 100, 0 /*deletefashion- naive delete*/);
		SystemDefs.compTID_PC_Index = new BTreeFile(PRED_CON_COMPOSITEINDEX, AttrType.attrString, 100, 0 /*deletefashion- naive delete*/);
		SystemDefs.compTID_OC_Index = new BTreeFile(OBJ_CON_COPOSITEINDEX, AttrType.attrString, 100, 0 /*deletefashion- naive delete*/);
		SystemDefs.compTID_SO_Index = new BTreeFile(SUB_OBJ_COMPOSITEINDEX, AttrType.attrString, 100, 0 /*deletefashion- naive delete*/);

		SystemDefs.compTID_SPO_Index = new BTreeFile(SPO_COMPOSITEINDEX, AttrType.attrString, 100, 0 /*deletefashion- naive delete*/);
	}


	public void initializeHeaps()
	{
		System.out.println("  - Create a heap file\n");
		try {
			entityLabelHeap = new LabelHeapFile(ENTITY_HEAPFILE);
			predicateLabelHeap = new LabelHeapFile(PREDICATE_HEAPFILE);
			tripleHeap = new TripleHeapfile(TRIPLE_HEAPFILE);

			SystemDefs.tupleHeap=new Heapfile("TupleHeap");
			SystemDefs.tripleHeapStream=new TripleHeapfile("TripleHeapStream");
			
			createLabelIndexFiles();
			createTripleIndexFiles();
			//create new btree file

			SystemDefs.entityLabelHeap = entityLabelHeap;
			SystemDefs.predicateLabelHeap = predicateLabelHeap;
			SystemDefs.tripleHeap=tripleHeap;
			PCounter.initialize();
			Stats.initialize();
		} catch (Exception e) {
			System.err.println("*** Could not create heap file\n");
			e.printStackTrace();
		}
	}

	/*
	 * : Initialize a stream of triples, where the subject label matches
	 * subjectFilter, predicate label matches predicateFilter, object label
	 * matches objectFilter, and confidence is greater than or equal to the
	 * confidenceFilter. If any of the filters are null strings or 0, then that
	 * filter is not considered
	 */
	public Stream openStream(String rdfdb, int orderType, String subjectFilter, String predicateFilter, String objectFilter,double confidenceFilter, int numbuf) throws InvalidSlotNumberException, InvalidTripleSizeException, THFException, THFDiskMgrException, THFBufMgrException, Exception
	{
		Stream s = new Stream(orderType, subjectFilter, predicateFilter, objectFilter, confidenceFilter, numbuf);
		return s;
	}

	/**
	 * Open the database with the given name.
	 * 
	 * @param name
	 *            DB_name
	 * 
	 * @exception IOException
	 *                I/O errors
	 * @exception FileIOException
	 *                file I/O error
	 * @exception InvalidPageNumberException
	 *                invalid page number
	 * @exception DiskMgrException
	 *                error caused by other layers
	 */
	public void openDB(String fname) throws IOException,
	InvalidPageNumberException, FileIOException, DiskMgrException {
		name = fname;

		// Creaat a random access file
		fp = new RandomAccessFile(fname, "rw");

		PageId pageId = new PageId();
		Page apage = new Page();
		pageId.pid = 0;

		num_pages = 1; // temporary num_page value for pinpage to work

		pinPage(pageId, apage, false /* read disk */);

		DBFirstPage firstpg = new DBFirstPage();
		firstpg.openPage(apage);
		num_pages = firstpg.getNumDBPages();

		unpinPage(pageId, false /* undirty */);
		initializeHeaps();
	}

	/**
	 * DB Constructors. Create a database with the specified number of pages
	 * where the page size is the default page size.
	 * 
	 * @param name
	 *            DB name
	 * @param num_pages
	 *            number of pages in DB
	 * 
	 * @exception IOException
	 *                I/O errors
	 * @exception InvalidPageNumberException
	 *                invalid page number
	 * @exception FileIOException
	 *                file I/O error
	 * @exception DiskMgrException
	 *                error caused by other layers
	 */
	public void openDB(String fname, int num_pgs) throws IOException,
	InvalidPageNumberException, FileIOException, DiskMgrException {
		name = new String(fname);
		num_pages = (num_pgs > 2) ? num_pgs : 2;

		File DBfile = new File(name);

		DBfile.delete();

		// Creaat a random access file
		fp = new RandomAccessFile(fname, "rw");

		// Make the file num_pages pages long, filled with zeroes.
		fp.seek((long) (num_pages * MINIBASE_PAGESIZE - 1));
		fp.writeByte(0);

		// Initialize space map and directory pages.

		// Initialize the first DB page
		Page apage = new Page();
		PageId pageId = new PageId();
		pageId.pid = 0;
		pinPage(pageId, apage, true /* no diskIO */);

		DBFirstPage firstpg = new DBFirstPage(apage);

		firstpg.setNumDBPages(num_pages);
		unpinPage(pageId, true /* dirty */);

		// Calculate how many pages are needed for the space map. Reserve pages
		// 0 and 1 and as many additional pages for the space map as are needed.
		int num_map_pages = (num_pages + bits_per_page - 1) / bits_per_page;

		set_bits(pageId, 1 + num_map_pages, 1);
		initializeHeaps();
	}

	/**
	 * Close DB file.
	 * 
	 * @exception IOException
	 *                I/O errors.
	 */
	public void closeDB() throws IOException {
		try{
			SystemDefs.JavabaseBM.flushAllPages();
			fp.close();
		}
		catch(Exception e){
			System.err.println (""+e);
			e.printStackTrace();
		}
	}

	/**
	 * Destroy the database, removing the file that stores it.
	 * 
	 * @exception IOException
	 *                I/O errors.
	 */
	public void DBDestroy() throws IOException {

		fp.close();
		File DBfile = new File(name);
		DBfile.delete();
	}

	/**
	 * Read the contents of the specified page into a Page object
	 * 
	 * @param pageno
	 *            pageId which will be read
	 * @param apage
	 *            page object which holds the contents of page
	 * 
	 * @exception InvalidPageNumberException
	 *                invalid page number
	 * @exception FileIOException
	 *                file I/O error
	 * @exception IOException
	 *                I/O errors
	 */
	public void read_page(PageId pageno, Page apage)
	throws InvalidPageNumberException, FileIOException, IOException {

		if ((pageno.pid < 0) || (pageno.pid >= num_pages))
			throw new InvalidPageNumberException(null, "BAD_PAGE_NUMBER");

		// Seek to the correct page
		fp.seek((long) (pageno.pid * MINIBASE_PAGESIZE));

		// Read the appropriate number of bytes.
		byte[] buffer = apage.getpage(); // new byte[MINIBASE_PAGESIZE];
		try {
			fp.read(buffer);
			PCounter.readIncrement();
		} catch (IOException e) {
			throw new FileIOException(e, "DB file I/O error");
		}

	}

	/**
	 * Write the contents in a page object to the specified page.
	 * 
	 * @param pageno
	 *            pageId will be wrote to disk
	 * @param apage
	 *            the page object will be wrote to disk
	 * 
	 * @exception InvalidPageNumberException
	 *                invalid page number
	 * @exception FileIOException
	 *                file I/O error
	 * @exception IOException
	 *                I/O errors
	 */
	public void write_page(PageId pageno, Page apage)
	throws InvalidPageNumberException, FileIOException, IOException {

		if ((pageno.pid < 0) || (pageno.pid >= num_pages))
			throw new InvalidPageNumberException(null, "INVALID_PAGE_NUMBER");

		// Seek to the correct page
		fp.seek((long) (pageno.pid * MINIBASE_PAGESIZE));

		// Write the appropriate number of bytes.
		try {
			fp.write(apage.getpage());
			PCounter.writeIncrement();
		} catch (IOException e) {
			throw new FileIOException(e, "DB file I/O error");
		}

	}

	/**
	 * Allocate a set of pages where the run size is taken to be 1 by default.
	 * Gives back the page number of the first page of the allocated run. with
	 * default run_size =1
	 * 
	 * @param start_page_num
	 *            page number to start with
	 * 
	 * @exception OutOfSpaceException
	 *                database is full
	 * @exception InvalidRunSizeException
	 *                invalid run size
	 * @exception InvalidPageNumberException
	 *                invalid page number
	 * @exception FileIOException
	 *                DB file I/O errors
	 * @exception IOException
	 *                I/O errors
	 * @exception DiskMgrException
	 *                error caused by other layers
	 */
	public void allocate_page(PageId start_page_num)
	throws OutOfSpaceException, InvalidRunSizeException,
	InvalidPageNumberException, FileIOException, DiskMgrException,
	IOException {
		allocate_page(start_page_num, 1);
	}

	/**
	 * user specified run_size
	 * 
	 * @param start_page_num
	 *            the starting page id of the run of pages
	 * @param run_size
	 *            the number of page need allocated
	 * 
	 * @exception OutOfSpaceException
	 *                No space left
	 * @exception InvalidRunSizeException
	 *                invalid run size
	 * @exception InvalidPageNumberException
	 *                invalid page number
	 * @exception FileIOException
	 *                file I/O error
	 * @exception IOException
	 *                I/O errors
	 * @exception DiskMgrException
	 *                error caused by other layers
	 */
	public void allocate_page(PageId start_page_num, int runsize)
	throws OutOfSpaceException, InvalidRunSizeException,
	InvalidPageNumberException, FileIOException, DiskMgrException,
	IOException {

		if (runsize < 0)
			throw new InvalidRunSizeException(null, "Negative run_size");

		int run_size = runsize;
		int num_map_pages = (num_pages + bits_per_page - 1) / bits_per_page;
		int current_run_start = 0;
		int current_run_length = 0;

		// This loop goes over each page in the space map.
		PageId pgid = new PageId();
		byte[] pagebuf;
		int byteptr;

		for (int i = 0; i < num_map_pages; ++i) {// start forloop01

			pgid.pid = 1 + i;
			// Pin the space-map page.

			Page apage = new Page();
			pinPage(pgid, apage, false /* read disk */);

			pagebuf = apage.getpage();
			byteptr = 0;

			// get the num of bits on current page
			int num_bits_this_page = num_pages - i * bits_per_page;
			if (num_bits_this_page > bits_per_page)
				num_bits_this_page = bits_per_page;

			// Walk the page looking for a sequence of 0 bits of the appropriate
			// length. The outer loop steps through the page's bytes, the inner
			// one steps through each byte's bits.

			for (; num_bits_this_page > 0 && current_run_length < run_size; ++byteptr) {// start
				// forloop02

				Integer intmask = new Integer(1);
				Byte mask = new Byte(intmask.byteValue());
				byte tmpmask = mask.byteValue();

				while (mask.intValue() != 0 && (num_bits_this_page > 0)
						&& (current_run_length < run_size))

				{
					if ((pagebuf[byteptr] & tmpmask) != 0) {
						current_run_start += current_run_length + 1;
						current_run_length = 0;
					} else
						++current_run_length;

					tmpmask <<= 1;
					mask = new Byte(tmpmask);
					--num_bits_this_page;
				}

			}// end of forloop02
			// Unpin the space-map page.

			unpinPage(pgid, false /* undirty */);

		}// end of forloop01

		if (current_run_length >= run_size) {
			start_page_num.pid = current_run_start;
			set_bits(start_page_num, run_size, 1);

			return;
		}

		throw new OutOfSpaceException(null, "No space left");
	}

	/**
	 * Deallocate a set of pages starting at the specified page number and a run
	 * size can be specified.
	 * 
	 * @param start_page_num
	 *            the start pageId to be deallocate
	 * @param run_size
	 *            the number of pages to be deallocated
	 * 
	 * @exception InvalidRunSizeException
	 *                invalid run size
	 * @exception InvalidPageNumberException
	 *                invalid page number
	 * @exception FileIOException
	 *                file I/O error
	 * @exception IOException
	 *                I/O errors
	 * @exception DiskMgrException
	 *                error caused by other layers
	 */
	public void deallocate_page(PageId start_page_num, int run_size)
	throws InvalidRunSizeException, InvalidPageNumberException,
	IOException, FileIOException, DiskMgrException {

		if (run_size < 0)
			throw new InvalidRunSizeException(null, "Negative run_size");

		set_bits(start_page_num, run_size, 0);
	}

	/**
	 * Deallocate a set of pages starting at the specified page number with run
	 * size = 1
	 * 
	 * @param start_page_num
	 *            the start pageId to be deallocate
	 * @param run_size
	 *            the number of pages to be deallocated
	 * 
	 * @exception InvalidRunSizeException
	 *                invalid run size
	 * @exception InvalidPageNumberException
	 *                invalid page number
	 * @exception FileIOException
	 *                file I/O error
	 * @exception IOException
	 *                I/O errors
	 * @exception DiskMgrException
	 *                error caused by other layers
	 * 
	 */
	public void deallocate_page(PageId start_page_num)
	throws InvalidRunSizeException, InvalidPageNumberException,
	IOException, FileIOException, DiskMgrException {

		set_bits(start_page_num, 1, 0);
	}

	/**
	 * Adds a file entry to the header page(s).
	 * 
	 * @param fname
	 *            file entry name
	 * @param start_page_num
	 *            the start page number of the file entry
	 * 
	 * @exception FileNameTooLongException
	 *                invalid file name (too long)
	 * @exception InvalidPageNumberException
	 *                invalid page number
	 * @exception InvalidRunSizeException
	 *                invalid DB run size
	 * @exception DuplicateEntryException
	 *                entry for DB is not unique
	 * @exception OutOfSpaceException
	 *                database is full
	 * @exception FileIOException
	 *                file I/O error
	 * @exception IOException
	 *                I/O errors
	 * @exception DiskMgrException
	 *                error caused by other layers
	 */
	public void add_file_entry(String fname, PageId start_page_num)
	throws FileNameTooLongException, InvalidPageNumberException,
	InvalidRunSizeException, DuplicateEntryException,
	OutOfSpaceException, FileIOException, IOException, DiskMgrException {

		if (fname.length() >= MAX_NAME)
			throw new FileNameTooLongException(null, "DB filename too long");
		if ((start_page_num.pid < 0) || (start_page_num.pid >= num_pages))
			throw new InvalidPageNumberException(null, " DB bad page number");

		// Does the file already exist?

		if (get_file_entry(fname) != null)
			throw new DuplicateEntryException(null,
			"DB fileentry already exists");

		Page apage = new Page();

		boolean found = false;
		int free_slot = 0;
		PageId hpid = new PageId();
		PageId nexthpid = new PageId(0);
		DBHeaderPage dp;
		do {// Start DO01
			// System.out.println("start do01");
			hpid.pid = nexthpid.pid;

			// Pin the header page
			pinPage(hpid, apage, false /* read disk */);

			// This complication is because the first page has a different
			// structure from that of subsequent pages.
			if (hpid.pid == 0) {
				dp = new DBFirstPage();
				((DBFirstPage) dp).openPage(apage);
			} else {
				dp = new DBDirectoryPage();
				((DBDirectoryPage) dp).openPage(apage);
			}

			nexthpid = dp.getNextPage();
			int entry = 0;

			PageId tmppid = new PageId();
			while (entry < dp.getNumOfEntries()) {
				dp.getFileEntry(tmppid, entry);
				if (tmppid.pid == INVALID_PAGE)
					break;
				entry++;
			}

			if (entry < dp.getNumOfEntries()) {
				free_slot = entry;
				found = true;
			} else if (nexthpid.pid != INVALID_PAGE) {
				// We only unpin if we're going to continue looping.
				unpinPage(hpid, false /* undirty */);
			}

		} while ((nexthpid.pid != INVALID_PAGE) && (!found)); // End of DO01

		// Have to add a new header page if possible.
		if (!found) {
			try {
				allocate_page(nexthpid);
			} catch (Exception e) { // need rethrow an exception!!!!
				unpinPage(hpid, false /* undirty */);
				e.printStackTrace();
			}

			// Set the next-page pointer on the previous directory page.
			dp.setNextPage(nexthpid);
			unpinPage(hpid, true /* dirty */);

			// Pin the newly-allocated directory page.
			hpid.pid = nexthpid.pid;

			pinPage(hpid, apage, true/* no diskIO */);
			dp = new DBDirectoryPage(apage);

			free_slot = 0;
		}

		// At this point, "hpid" has the page id of the header page with the
		// free
		// slot; "pg" points to the pinned page; "dp" has the directory_page
		// pointer; "free_slot" is the entry number in the directory where we're
		// going to put the new file entry.

		dp.setFileEntry(start_page_num, fname, free_slot);

		unpinPage(hpid, true /* dirty */);

	}

	/**
	 * Delete the entry corresponding to a file from the header page(s).
	 * 
	 * @param fname
	 *            file entry name
	 * 
	 * @exception FileEntryNotFoundException
	 *                file does not exist
	 * @exception FileIOException
	 *                file I/O error
	 * @exception IOException
	 *                I/O errors
	 * @exception InvalidPageNumberException
	 *                invalid page number
	 * @exception DiskMgrException
	 *                error caused by other layers
	 */
	public void delete_file_entry(String fname)
	throws FileEntryNotFoundException, IOException, FileIOException,
	InvalidPageNumberException, DiskMgrException {

		Page apage = new Page();
		boolean found = false;
		int slot = 0;
		PageId hpid = new PageId();
		PageId nexthpid = new PageId(0);
		PageId tmppid = new PageId();
		DBHeaderPage dp;

		do { // startDO01
			hpid.pid = nexthpid.pid;

			// Pin the header page.
			pinPage(hpid, apage, false/* read disk */);

			// This complication is because the first page has a different
			// structure from that of subsequent pages.
			if (hpid.pid == 0) {
				dp = new DBFirstPage();
				((DBFirstPage) dp).openPage(apage);
			} else {
				dp = new DBDirectoryPage();
				((DBDirectoryPage) dp).openPage(apage);
			}
			nexthpid = dp.getNextPage();

			int entry = 0;

			String tmpname;
			while (entry < dp.getNumOfEntries()) {
				tmpname = dp.getFileEntry(tmppid, entry);

				if ((tmppid.pid != INVALID_PAGE)
						&& (tmpname.compareTo(fname) == 0))
					break;
				entry++;
			}

			if (entry < dp.getNumOfEntries()) {
				slot = entry;
				found = true;
			} else {
				unpinPage(hpid, false /* undirty */);
			}

		} while ((nexthpid.pid != INVALID_PAGE) && (!found)); // EndDO01

		if (!found) // Entry not found - nothing deleted
			throw new FileEntryNotFoundException(null, "DB file not found");

		// Have to delete record at hpnum:slot
		tmppid.pid = INVALID_PAGE;
		dp.setFileEntry(tmppid, "\0", slot);

		unpinPage(hpid, true /* dirty */);

	}

	/**
	 * Get the entry corresponding to the given file.
	 * 
	 * @param name
	 *            file entry name
	 * 
	 * @exception IOException
	 *                I/O errors
	 * @exception FileIOException
	 *                file I/O error
	 * @exception InvalidPageNumberException
	 *                invalid page number
	 * @exception DiskMgrException
	 *                error caused by other layers
	 */
	public PageId get_file_entry(String name) throws IOException,
	FileIOException, InvalidPageNumberException, DiskMgrException {

		Page apage = new Page();
		boolean found = false;
		int slot = 0;
		PageId hpid = new PageId();
		PageId nexthpid = new PageId(0);
		DBHeaderPage dp;

		do {// Start DO01

			// System.out.println("get_file_entry do-loop01: "+name);
			hpid.pid = nexthpid.pid;

			// Pin the header page.
			pinPage(hpid, apage, false /* no diskIO */);

			// This complication is because the first page has a different
			// structure from that of subsequent pages.
			if (hpid.pid == 0) {
				dp = new DBFirstPage();
				((DBFirstPage) dp).openPage(apage);
			} else {
				dp = new DBDirectoryPage();
				((DBDirectoryPage) dp).openPage(apage);
			}
			nexthpid = dp.getNextPage();

			int entry = 0;
			PageId tmppid = new PageId();
			String tmpname;

			while (entry < dp.getNumOfEntries()) {
				tmpname = dp.getFileEntry(tmppid, entry);

				if ((tmppid.pid != INVALID_PAGE)
						&& (tmpname.compareTo(name) == 0))
					break;
				entry++;
			}
			if (entry < dp.getNumOfEntries()) {
				slot = entry;
				found = true;
			}

			unpinPage(hpid, false /* undirty */);

		} while ((nexthpid.pid != INVALID_PAGE) && (!found));// End of DO01

		if (!found) // Entry not found - don't post error, just fail.
		{
			// System.out.println("entry NOT found");
			return null;
		}

		PageId startpid = new PageId();
		dp.getFileEntry(startpid, slot);
		return startpid;
	}

	/**
	 * Functions to return some characteristics of the database.
	 */
	public String db_name() {
		return name;
	}

	public int db_num_pages() {
		return num_pages;
	}

	public int db_page_size() {
		return MINIBASE_PAGESIZE;
	}

	/**
	 * Print out the space map of the database. The space map is a bitmap
	 * showing which pages of the db are currently allocated.
	 * 
	 * @exception FileIOException
	 *                file I/O error
	 * @exception IOException
	 *                I/O errors
	 * @exception InvalidPageNumberException
	 *                invalid page number
	 * @exception DiskMgrException
	 *                error caused by other layers
	 */
	public void dump_space_map() throws DiskMgrException, IOException,
	FileIOException, InvalidPageNumberException

	{

		System.out.println("********  IN DUMP");
		int num_map_pages = (num_pages + bits_per_page - 1) / bits_per_page;
		int bit_number = 0;

		// This loop goes over each page in the space map.
		PageId pgid = new PageId();
		System.out.println("num_map_pages = " + num_map_pages);
		System.out.println("num_pages = " + num_pages);
		for (int i = 0; i < num_map_pages; i++) {// start forloop01

			pgid.pid = 1 + i; // space map starts at page1
			// Pin the space-map page.
			Page apage = new Page();
			pinPage(pgid, apage, false/* read disk */);

			// How many bits should we examine on this page?
			int num_bits_this_page = num_pages - i * bits_per_page;
			System.out.println("num_bits_this_page = " + num_bits_this_page);
			System.out.println("num_pages = " + num_pages);
			if (num_bits_this_page > bits_per_page)
				num_bits_this_page = bits_per_page;

			// Walk the page looking for a sequence of 0 bits of the appropriate
			// length. The outer loop steps through the page's bytes, the inner
			// one steps through each byte's bits.

			int pgptr = 0;
			byte[] pagebuf = apage.getpage();
			int mask;
			for (; num_bits_this_page > 0; pgptr++) {// start forloop02

				for (mask = 1; mask < 256 && num_bits_this_page > 0; mask = (mask << 1), --num_bits_this_page, ++bit_number) {// start
					// forloop03

					int bit = pagebuf[pgptr] & mask;
					if ((bit_number % 10) == 0)
						if ((bit_number % 50) == 0) {
							if (bit_number > 0)
								System.out.println("\n");
							System.out.print("\t" + bit_number + ": ");
						} else
							System.out.print(' ');

					if (bit != 0)
						System.out.print("1");
					else
						System.out.print("0");

				}// end of forloop03

			}// end of forloop02

			unpinPage(pgid, false /* undirty */);

		}// end of forloop01

		System.out.println();

	}

	private RandomAccessFile fp;
	private int num_pages;
	private String name;

	/**
	 * Set runsize bits starting from start to value specified
	 */
	private void set_bits(PageId start_page, int run_size, int bit)
	throws InvalidPageNumberException, FileIOException, IOException,
	DiskMgrException {

		if ((start_page.pid < 0) || (start_page.pid + run_size > num_pages))
			throw new InvalidPageNumberException(null, "Bad page number");

		// Locate the run within the space map.
		int first_map_page = start_page.pid / bits_per_page + 1;
		int last_map_page = (start_page.pid + run_size - 1) / bits_per_page + 1;
		int first_bit_no = start_page.pid % bits_per_page;

		// The outer loop goes over all space-map pages we need to touch.

		for (PageId pgid = new PageId(first_map_page); pgid.pid <= last_map_page; pgid.pid = pgid.pid + 1, first_bit_no = 0) {// Start
			// forloop01

			// Pin the space-map page.
			Page pg = new Page();

			pinPage(pgid, pg, false/* no diskIO */);

			byte[] pgbuf = pg.getpage();

			// Locate the piece of the run that fits on this page.
			int first_byte_no = first_bit_no / 8;
			int first_bit_offset = first_bit_no % 8;
			int last_bit_no = first_bit_no + run_size - 1;

			if (last_bit_no >= bits_per_page)
				last_bit_no = bits_per_page - 1;

			int last_byte_no = last_bit_no / 8;

			// This loop actually flips the bits on the current page.
			int cur_posi = first_byte_no;
			for (; cur_posi <= last_byte_no; ++cur_posi, first_bit_offset = 0) {// start
				// forloop02

				int max_bits_this_byte = 8 - first_bit_offset;
				int num_bits_this_byte = (run_size > max_bits_this_byte ? max_bits_this_byte
						: run_size);

				int imask = 1;
				int temp;
				imask = ((imask << num_bits_this_byte) - 1) << first_bit_offset;
				Integer intmask = new Integer(imask);
				Byte mask = new Byte(intmask.byteValue());
				byte bytemask = mask.byteValue();

				if (bit == 1) {
					temp = (pgbuf[cur_posi] | bytemask);
					intmask = new Integer(temp);
					pgbuf[cur_posi] = intmask.byteValue();
				} else {

					temp = pgbuf[cur_posi] & (255 ^ bytemask);
					intmask = new Integer(temp);
					pgbuf[cur_posi] = intmask.byteValue();
				}
				run_size -= num_bits_this_byte;

			}// end of forloop02

			// Unpin the space-map page.

			unpinPage(pgid, true /* dirty */);

		}// end of forloop01

	}

	/**
	 * short cut to access the pinPage function in bufmgr package.
	 * 
	 * @see bufmgr.pinPage
	 */
	private void pinPage(PageId pageno, Page page, boolean emptyPage)
	throws DiskMgrException {

		try {
			SystemDefs.JavabaseBM.pinPage(pageno, page, emptyPage);
		} catch (Exception e) {
			throw new DiskMgrException(e, "DB.java: pinPage() failed");
		}

	} // end of pinPage

	/**
	 * short cut to access the unpinPage function in bufmgr package.
	 * 
	 * @see bufmgr.unpinPage
	 */
	private void unpinPage(PageId pageno, boolean dirty)
	throws DiskMgrException {

		try {
			SystemDefs.JavabaseBM.unpinPage(pageno, dirty);
		} catch (Exception e) {
			throw new DiskMgrException(e, "DB.java: unpinPage() failed");
		}

	} // end of unpinPage

}// End of RdfDB class.

/**
 * interface of PageUsedBytes
 */
interface PageUsedBytes {
	int DIR_PAGE_USED_BYTES = 8 + 8;
	int FIRST_PAGE_USED_BYTES = DIR_PAGE_USED_BYTES + 4;
}

/**
 * Super class of the directory page and first page
 */
class DBHeaderPage implements PageUsedBytes, GlobalConst {

	protected static final int NEXT_PAGE = 0;
	protected static final int NUM_OF_ENTRIES = 4;
	protected static final int START_FILE_ENTRIES = 8;
	protected static final int SIZE_OF_FILE_ENTRY = 4 + MAX_NAME + 2;

	protected byte[] data;

	/**
	 * Default constructor
	 */
	public DBHeaderPage() {
	}

	/**
	 * Constrctor of class DBHeaderPage
	 * 
	 * @param page
	 *            a page of Page object
	 * @param pageusedbytes
	 *            number of bytes used on the page
	 * @exception IOException
	 */
	public DBHeaderPage(Page page, int pageusedbytes) throws IOException {
		data = page.getpage();
		PageId pageno = new PageId();
		pageno.pid = INVALID_PAGE;
		setNextPage(pageno);

		PageId temppid = getNextPage();

		int num_entries = (MAX_SPACE - pageusedbytes) / SIZE_OF_FILE_ENTRY;
		setNumOfEntries(num_entries);

		for (int index = 0; index < num_entries; ++index)
			initFileEntry(INVALID_PAGE, index);
	}

	/**
	 * set the next page number
	 * 
	 * @param pageno
	 *            next page ID
	 * @exception IOException
	 *                I/O errors
	 */
	public void setNextPage(PageId pageno) throws IOException {
		Convert.setIntValue(pageno.pid, NEXT_PAGE, data);
	}

	/**
	 * return the next page number
	 * 
	 * @return next page ID
	 * @exception IOException
	 *                I/O errors
	 */
	public PageId getNextPage() throws IOException {
		PageId nextPage = new PageId();
		nextPage.pid = Convert.getIntValue(NEXT_PAGE, data);
		return nextPage;
	}

	/**
	 * set number of entries on this page
	 * 
	 * @param numEntries
	 *            the number of entries
	 * @exception IOException
	 *                I/O errors
	 */

	protected void setNumOfEntries(int numEntries) throws IOException {
		Convert.setIntValue(numEntries, NUM_OF_ENTRIES, data);
	}

	/**
	 * return the number of file entries on the page
	 * 
	 * @return number of entries
	 * @exception IOException
	 *                I/O errors
	 */
	public int getNumOfEntries() throws IOException {
		return Convert.getIntValue(NUM_OF_ENTRIES, data);
	}

	/**
	 * initialize file entries as empty
	 * 
	 * @param empty
	 *            invalid page number (=-1)
	 * @param entryno
	 *            file entry number
	 * @exception IOException
	 *                I/O errors
	 */
	private void initFileEntry(int empty, int entryNo) throws IOException {
		int position = START_FILE_ENTRIES + entryNo * SIZE_OF_FILE_ENTRY;
		Convert.setIntValue(empty, position, data);
	}

	/**
	 * set file entry
	 * 
	 * @param pageno
	 *            page ID
	 * @param fname
	 *            the file name
	 * @param entryno
	 *            file entry number
	 * @exception IOException
	 *                I/O errors
	 */
	public void setFileEntry(PageId pageNo, String fname, int entryNo)
	throws IOException {

		int position = START_FILE_ENTRIES + entryNo * SIZE_OF_FILE_ENTRY;
		Convert.setIntValue(pageNo.pid, position, data);
		Convert.setStrValue(fname, position + 4, data);
	}

	/**
	 * return file entry info
	 * 
	 * @param pageno
	 *            page Id
	 * @param entryNo
	 *            the file entry number
	 * @return file name
	 * @exception IOException
	 *                I/O errors
	 */
	public String getFileEntry(PageId pageNo, int entryNo) throws IOException {

		int position = START_FILE_ENTRIES + entryNo * SIZE_OF_FILE_ENTRY;
		pageNo.pid = Convert.getIntValue(position, data);
		return (Convert.getStrValue1(position + 4, data, MAX_NAME + 2));
	}

}

/**
 * DBFirstPage class which is a subclass of DBHeaderPage class
 */
class DBFirstPage extends DBHeaderPage {

	protected static final int NUM_DB_PAGE = MINIBASE_PAGESIZE - 4;

	/**
	 * Default construtor
	 */
	public DBFirstPage() {
		super();
	}

	/**
	 * Constructor of class DBFirstPage class
	 * 
	 * @param page
	 *            a page of Page object
	 * @exception IOException
	 *                I/O errors
	 */
	public DBFirstPage(Page page) throws IOException {
		super(page, FIRST_PAGE_USED_BYTES);
	}

	/**
	 * open an exist DB first page
	 * 
	 * @param page
	 *            a page of Page object
	 */
	public void openPage(Page page) {
		data = page.getpage();
	}

	/**
	 * set number of pages in the DB
	 * 
	 * @param num
	 *            the number of pages in DB
	 * @exception IOException
	 *                I/O errors
	 */
	public void setNumDBPages(int num) throws IOException {
		Convert.setIntValue(num, NUM_DB_PAGE, data);
	}

	/**
	 * return the number of pages in the DB
	 * 
	 * @return number of pages in DB
	 * @exception IOException
	 *                I/O errors
	 */
	public int getNumDBPages() throws IOException {

		return (Convert.getIntValue(NUM_DB_PAGE, data));
	}

}

/**
 * DBDirectoryPage class which is a subclass of DBHeaderPage class
 */
class DBDirectoryPage extends DBHeaderPage { // implements PageUsedBytes

	/**
	 * Default constructor
	 */
	public DBDirectoryPage() {
		super();
	}

	/**
	 * Constructor of DBDirectoryPage class
	 * 
	 * @param page
	 *            a page of Page object
	 * @exception IOException
	 */
	public DBDirectoryPage(Page page) throws IOException {
		super(page, DIR_PAGE_USED_BYTES);
	}

	/**
	 * open an exist DB directory page
	 * 
	 * @param page
	 *            a page of Page object
	 */
	public void openPage(Page page) {
		data = page.getpage();
	}

}
